home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / telnet.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  9KB  |  492 lines

  1. #include <stdio.h>
  2. #include "config.h"
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "timer.h"
  6. #include "icmp.h"
  7. #include "netuser.h"
  8. #include "tcp.h"
  9. #include "telnet.h"
  10. #include "session.h"
  11. #include "ftp.h"
  12. #include "iface.h"
  13. #include "ax25.h"
  14. #include "lapb.h"
  15. #include "finger.h"
  16. #include "nr4.h"
  17. #ifdef    UNIX
  18. #include <string.h>
  19. #endif
  20.  
  21. #define    CTLZ    26
  22.  
  23. extern char nospace[];
  24. extern char badhost[];
  25. int refuse_echo = 0;
  26. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  27.  
  28. #ifdef    DEBUG
  29. char *t_options[] = {
  30.     "Transmit Binary",
  31.     "Echo",
  32.     "",
  33.     "Suppress Go Ahead",
  34.     "",
  35.     "Status",
  36.     "Timing Mark"
  37. };
  38. #endif
  39.  
  40. /* Execute user telnet command */
  41. int
  42. dotelnet(argc,argv)
  43. int argc;
  44. char *argv[];
  45. {
  46.     void t_state(),rcv_char(),tn_tx();
  47.     char *inet_ntoa();
  48.     int32 resolve();
  49.     int send_tel();
  50.         int unix_send_tel();
  51.     struct session *s;
  52.     struct telnet *tn;
  53.     struct tcb *tcb;
  54.     struct socket lsocket,fsocket;
  55.  
  56.  
  57.     lsocket.address = ip_addr;
  58.     lsocket.port = lport++;
  59.     if((fsocket.address = resolve(argv[1])) == 0){
  60.         printf(badhost,argv[1]);
  61.         return 1;
  62.     }
  63.     if(argc < 3)
  64.         fsocket.port = TELNET_PORT;
  65.     else
  66.         fsocket.port = atoi(argv[2]);
  67.  
  68.     /* Allocate a session descriptor */
  69.     if((s = newsession()) == NULLSESSION){
  70.         printf("Too many sessions\n");
  71.         return 1;
  72.     }
  73.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  74.         strcpy(s->name,argv[1]);
  75.     s->type = TELNET;
  76.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  77.         s->parse = unix_send_tel;
  78.     } else {
  79.         s->parse = send_tel;
  80.     }
  81.     current = s;
  82.  
  83.     /* Create and initialize a Telnet protocol descriptor */
  84.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  85.         printf(nospace);
  86.         s->type = FREE;
  87.         return 1;
  88.     }
  89.     tn->session = s;    /* Upward pointer */
  90.     tn->state = TS_DATA;
  91.     s->cb.telnet = tn;    /* Downward pointer */
  92.  
  93.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  94.      rcv_char,tn_tx,t_state,0,(char *)tn);
  95.  
  96.     tn->tcb = tcb;    /* Downward pointer */
  97.     go();
  98.     return 0;
  99. }
  100.  
  101. /* Process typed characters */
  102. int
  103. unix_send_tel(buf,n)
  104. char *buf;
  105. int16 n;
  106. {
  107.     int i;
  108.  
  109.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  110.         ;
  111.     if (buf[i] == '\r') {
  112.         buf[i] = '\n';
  113.         n = i+1;
  114.     }
  115.     send_tel(buf,n);
  116. }
  117. int
  118. send_tel(buf,n)
  119. char *buf;
  120. int16 n;
  121. {
  122.     struct mbuf *bp,*qdata();
  123.     if(current == NULLSESSION || current->cb.telnet == NULLTN
  124.      || current->cb.telnet->tcb == NULLTCB)
  125.         return;
  126.     /* If we're doing our own echoing and recording is enabled, record it */
  127.     if(!current->cb.telnet->remote[TN_ECHO] && current->record != NULLFILE)
  128.         fwrite(buf,1,(int)n,current->record);
  129.     bp = qdata(buf,n);
  130.     send_tcp(current->cb.telnet->tcb,bp);
  131. }
  132.  
  133. /* Process incoming TELNET characters */
  134. int
  135. tel_input(tn,bp)
  136. register struct telnet *tn;
  137. struct mbuf *bp;
  138. {
  139.     char c;
  140.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  141.     FILE *record;
  142.     char *memchr();
  143.  
  144.     /* Optimization for very common special case -- no special chars */
  145.     if(tn->state == TS_DATA){
  146.         while(bp != NULLBUF && memchr(bp->data,IAC,(int)bp->cnt) == NULLCHAR){
  147.             if((record = tn->session->record) != NULLFILE)
  148.                 fwrite(bp->data,1,(int)bp->cnt,record);
  149.             while(bp->cnt-- != 0)
  150.                 putchar(*bp->data++);
  151.             bp = free_mbuf(bp);
  152.         }
  153.     }
  154.     while(pullup(&bp,&c,1) == 1){
  155.         switch(tn->state){
  156.         case TS_DATA:
  157.             if(uchar(c) == IAC){
  158.                 tn->state = TS_IAC;
  159.             } else {
  160.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  161.                     c &= 0x7f;
  162.                 putchar(c);
  163.                 if((record = tn->session->record) != NULLFILE)
  164.                     putc(c,record);
  165.             }
  166.             break;
  167.         case TS_IAC:
  168.             switch(uchar(c)){
  169.             case WILL:
  170.                 tn->state = TS_WILL;
  171.                 break;
  172.             case WONT:
  173.                 tn->state = TS_WONT;
  174.                 break;
  175.             case DO:
  176.                 tn->state = TS_DO;
  177.                 break;
  178.             case DONT:
  179.                 tn->state = TS_DONT;
  180.                 break;
  181.             case IAC:
  182.                 putchar(c);
  183.                 tn->state = TS_DATA;
  184.                 break;
  185.             default:
  186.                 tn->state = TS_DATA;
  187.                 break;
  188.             }
  189.             break;
  190.         case TS_WILL:
  191.             willopt(tn,c);
  192.             tn->state = TS_DATA;
  193.             break;
  194.         case TS_WONT:
  195.             wontopt(tn,c);
  196.             tn->state = TS_DATA;
  197.             break;
  198.         case TS_DO:
  199.             doopt(tn,c);
  200.             tn->state = TS_DATA;
  201.             break;
  202.         case TS_DONT:
  203.             dontopt(tn,c);
  204.             tn->state = TS_DATA;
  205.             break;
  206.         }
  207.     }
  208. }
  209.  
  210. /* Telnet receiver upcall routine */
  211. void
  212. rcv_char(tcb,cnt)
  213. register struct tcb *tcb;
  214. int16 cnt;
  215. {
  216.     struct mbuf *bp;
  217.     struct telnet *tn;
  218.     FILE *record;
  219. #ifdef    FLOW
  220.     extern int ttyflow;
  221. #endif
  222.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  223.         /* Unknown connection; ignore it */
  224.         return;
  225.     }
  226.     /* Hold output if we're not the current session */
  227.     if(mode != CONV_MODE || current == NULLSESSION
  228. #ifdef    FLOW
  229.      || !ttyflow    /* Or if blocked by keyboard input -- hyc */
  230. #endif
  231.      || current->type != TELNET || current->cb.telnet != tn)
  232.         return;
  233.  
  234.     if(recv_tcp(tcb,&bp,cnt) > 0)
  235.         tel_input(tn,bp);
  236.  
  237.     fflush(stdout);
  238.     if((record = tn->session->record) != NULLFILE)
  239.         fflush(record);
  240. }
  241. /* Handle transmit upcalls. Used only for file uploading */
  242. void
  243. tn_tx(tcb,cnt)
  244. struct tcb *tcb;
  245. int16 cnt;
  246. {
  247.     struct telnet *tn;
  248.     struct session *s;
  249.     struct mbuf *bp;
  250.     int size;
  251.  
  252.     if((tn = (struct telnet *)tcb->user) == NULLTN
  253.      || (s = tn->session) == NULLSESSION
  254.      || s->upload == NULLFILE)
  255.         return;
  256.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  257.         return;
  258.     if((size = fread(bp->data,1,(int)cnt,s->upload)) > 0){
  259.         bp->cnt = (int16)size;
  260.         send_tcp(tcb,bp);
  261.     } else {
  262.         free_p(bp);
  263.     }
  264.     if(size != cnt){
  265.         /* Error or end-of-file */
  266.         fclose(s->upload);
  267.         s->upload = NULLFILE;
  268.         free(s->ufile);
  269.         s->ufile = NULLCHAR;
  270.     }
  271. }
  272.  
  273. /* State change upcall routine */
  274. /*ARGSUSED*/
  275. void
  276. t_state(tcb,old,new)
  277. register struct tcb *tcb;
  278. char old,new;
  279. {
  280.     struct telnet *tn;
  281.     char notify = 0;
  282.     extern char *tcpstates[];
  283.     extern char *reasons[];
  284.     extern char *unreach[];
  285.     extern char *exceed[];
  286.  
  287.     /* Can't add a check for unknown connection here, it would loop
  288.      * on a close upcall! We're just careful later on.
  289.      */
  290.     tn = (struct telnet *)tcb->user;
  291.  
  292.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  293.     {
  294.         notify = 1;
  295.         cooked();    /* prettify things... -- hyc */
  296.     }
  297.  
  298.     switch(new){
  299.     case CLOSE_WAIT:
  300.         if(notify)
  301.             printf("%s\n",tcpstates[new]);
  302.         close_tcp(tcb);
  303.         break;
  304.     case CLOSED:    /* court adjourned */
  305.         if(notify){
  306.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  307.             if(tcb->reason == NETWORK){
  308.                 switch(tcb->type){
  309.                 case DEST_UNREACH:
  310.                     printf(": %s unreachable",unreach[tcb->code]);
  311.                     break;
  312.                 case TIME_EXCEED:
  313.                     printf(": %s time exceeded",exceed[tcb->code]);
  314.                     break;
  315.                 }
  316.             }
  317.             printf(")\n");
  318.             cmdmode();
  319.         }
  320.         del_tcp(tcb);
  321.         if(tn != NULLTN)
  322.             free_telnet(tn);
  323.         break;
  324.     default:
  325.         if(notify)
  326.             printf("%s\n",tcpstates[new]);
  327.         break;
  328.     }
  329.     fflush(stdout);
  330. }
  331. /* Delete telnet structure */
  332. static
  333. free_telnet(tn)
  334. struct telnet *tn;
  335. {
  336.     if(tn->session != NULLSESSION)
  337.         freesession(tn->session);
  338.  
  339.     if(tn != NULLTN)
  340.         free((char *)tn);
  341. }
  342.  
  343. /* The guts of the actual Telnet protocol: negotiating options */
  344. void
  345. willopt(tn,opt)
  346. struct telnet *tn;
  347. char opt;
  348. {
  349.     int ack;
  350.     void answer();
  351.  
  352. #ifdef    DEBUG
  353.     printf("recv: will ");
  354.     if(uchar(opt) <= NOPTIONS)
  355.         printf("%s\n",t_options[opt]);
  356.     else
  357.         printf("%u\n",opt);
  358. #endif
  359.     
  360.     switch(uchar(opt)){
  361.     case TN_TRANSMIT_BINARY:
  362.     case TN_ECHO:
  363.     case TN_SUPPRESS_GA:
  364.         if(tn->remote[uchar(opt)] == 1)
  365.             return;        /* Already set, ignore to prevent loop */
  366.         if(uchar(opt) == TN_ECHO){
  367.             if(refuse_echo){
  368.                 /* User doesn't want to accept */
  369.                 ack = DONT;
  370.                 break;
  371.             } else
  372.                 raw();        /* Put tty into raw mode */
  373.         }
  374.         tn->remote[uchar(opt)] = 1;
  375.         ack = DO;            
  376.         break;
  377.     default:
  378.         ack = DONT;    /* We don't know what he's offering; refuse */
  379.     }
  380.     answer(tn,ack,opt);
  381. }
  382. void
  383. wontopt(tn,opt)
  384. struct telnet *tn;
  385. char opt;
  386. {
  387.     void answer();
  388.  
  389. #ifdef    DEBUG
  390.     printf("recv: wont ");
  391.     if(uchar(opt) <= NOPTIONS)
  392.         printf("%s\n",t_options[uchar(opt)]);
  393.     else
  394.         printf("%u\n",uchar(opt));
  395. #endif
  396.     if(uchar(opt) <= NOPTIONS){
  397.         if(tn->remote[uchar(opt)] == 0)
  398.             return;        /* Already clear, ignore to prevent loop */
  399.         tn->remote[uchar(opt)] = 0;
  400.         if(uchar(opt) == TN_ECHO)
  401.             cooked();    /* Put tty into cooked mode */
  402.     }
  403.     answer(tn,DONT,opt);    /* Must always accept */
  404. }
  405. void
  406. doopt(tn,opt)
  407. struct telnet *tn;
  408. char opt;
  409. {
  410.     void answer();
  411.     int ack;
  412.  
  413. #ifdef    DEBUG
  414.     printf("recv: do ");
  415.     if(uchar(opt) <= NOPTIONS)
  416.         printf("%s\n",t_options[uchar(opt)]);
  417.     else
  418.         printf("%u\n",uchar(opt));
  419. #endif
  420.     switch(uchar(opt)){
  421. #ifdef    FUTURE    /* Use when local options are implemented */
  422.         if(tn->local[uchar(opt)] == 1)
  423.             return;        /* Already set, ignore to prevent loop */
  424.         tn->local[uchar(opt)] = 1;
  425.         ack = WILL;
  426.         break;
  427. #endif
  428.     default:
  429.         ack = WONT;    /* Don't know what it is */
  430.     }
  431.     answer(tn,ack,opt);
  432. }
  433. void
  434. dontopt(tn,opt)
  435. struct telnet *tn;
  436. char opt;
  437. {
  438.     void answer();
  439.  
  440. #ifdef    DEBUG
  441.     printf("recv: dont ");
  442.     if(uchar(opt) <= NOPTIONS)
  443.         printf("%s\n",t_options[uchar(opt)]);
  444.     else
  445.         printf("%u\n",uchar(opt));
  446. #endif
  447.     if(uchar(opt) <= NOPTIONS){
  448.         if(tn->local[uchar(opt)] == 0){
  449.             /* Already clear, ignore to prevent loop */
  450.             return;
  451.         }
  452.         tn->local[uchar(opt)] = 0;
  453.     }
  454.     answer(tn,WONT,opt);
  455. }
  456. static
  457. void
  458. answer(tn,r1,r2)
  459. struct telnet *tn;
  460. int r1,r2;
  461. {
  462.     struct mbuf *bp,*qdata();
  463.     char s[3];
  464.  
  465. #ifdef    DEBUG
  466.     switch(r1){
  467.     case WILL:
  468.         printf("sent: will ");
  469.         break;
  470.     case WONT:
  471.         printf("sent: wont ");
  472.         break;
  473.     case DO:
  474.         printf("sent: do ");
  475.         break;
  476.     case DONT:
  477.         printf("sent: dont ");
  478.         break;
  479.     }
  480.     if(r2 <= 6)
  481.         printf("%s\n",t_options[r2]);
  482.     else
  483.         printf("%u\n",r2);
  484. #endif
  485.  
  486.     s[0] = IAC;
  487.     s[1] = r1;
  488.     s[2] = r2;
  489.     bp = qdata(s,(int16)3);
  490.     send_tcp(tn->tcb,bp);
  491. }
  492.